# -*- coding: utf-8 -*-

from .models import *
from .utils import *
from .signals import *
import re
from metlib.shell.fileutil import *
from django.shortcuts import render
from django.http import HttpResponse, HttpResponseRedirect, JsonResponse, \
    HttpResponseNotFound, Http404, \
    HttpResponseServerError, HttpResponseNotAllowed, \
    HttpResponseBadRequest
from metlib.misc.datatype import Null
from metlib.misc.misc import gen_uuid8, parse_bool
from weblib.django.http.response import file_response
from weblib.django.setting import get_setting
# 此部分判断暂时没有实际用上
installed_apps = get_setting('INSTALLED_APPS', [])
if 'filecache' not in installed_apps:
    _HAS_FILECACHE = False
else:
    _HAS_FILECACHE = True
    try:
        from filecache.models import *
        from filecache.utils import *
    except ImportError:
        _HAS_FILECACHE = False

# 无可用数据时的http response.
response_nodata = ExceptionJsonResponse({"status": "Error", "reason": "No Data."})

class DataKeeper(object):
    """负责管理数据集, 并对外提供查询, 取数据等统一接口的管理员.
    """
    def __init__(self, name='DefaultKeeper', filecache_manager=None, control=None, datasets=None):
        self.name = name
        self.molds = DatasetMold.objects.all()
        if datasets is None:
            self.datasets = DataSet.objects.all()
        else:
            self.datasets = DataSet.objects.filter(pk__in=datasets)
        self.filecache_manager = filecache_manager
        self.control = control

    def lookup(self, info, request=None, *args, **kwargs):
        """查询功能的实际实现.
        Finalized on 20150825
        :param info:
        :param args:
        :param kwargs:
        :return: 结果列表.
        """
        results = []
        scope = self.datasets.filter(public=True)
        if self.control == 'user':
            user = kwargs.pop('user')
            if hasattr(user, 'data_setting'):
                # TODO: Company
                user_accessible_scope = user.data_setting.accessible_datasets.all()
                scope = scope | user_accessible_scope

        if "dataset_type" in info:
            scope = scope.filter(mold__name=info["dataset_type"]).distinct().order_by('priority')
        elif "dataset_tags" in info:
            tags = info['dataset_tags']
            if isinstance(tags, (str, unicode)):
                tags = tags.split(',')

            # TODO: 现在是or的关系, 将来可设法实现and
            scope = scope.filter(tags__in=tags).distinct().order_by('priority')
        else:
            scope = scope.distinct().order_by('priority')
        for dataset in scope:
            try:
                res = dataset.lookup(info, request=request, *args, **kwargs)
                if res is not None and len(res) != 0:
                    results.extend(res)
            except NotImplementedError:
                pass
            except Exception as e:
                pass
        return results

    def lookup_view(self, request, *args, **kwargs):
        """查询接口(lookup)的Django View,
        Finalized on 20150825
        :param request:
        :param args:
        :param kwargs:
        :return: 查找结果的JsonResponse
        """
        try:
            if request.method not in ('GET', 'POST'):
                return HttpResponseNotAllowed(['GET', 'POST'])
            if request.method == 'GET':
                info = request.GET.dict()
            else:
                info = request.POST.dict()

            if self.control == 'user':
                kwargs['user'] = request.user

            results = self.lookup(info, request=request, *args, **kwargs)
            result_dict = {
                "status": "OK",
                "reason": "",
                "objects": results
            }
            return JsonResponse(result_dict)
        except Exception as e:
            result_dict = {
                "status": "Error",
                "reason": unicode(e),
                "objects": []
            }
            import pdb
            pdb.set_trace()
            return ExceptionJsonResponse(result_dict)
    def data_view_schema(self, request, uri, *args, **kwargs):
        """查询接口(lookup)的Django View,
        Finalized on 20150825
        :param request:
        :param args:
        :param kwargs:
        :return: 查找结果的JsonResponse
        """
        try:
            if request.method not in ('GET', 'POST'):
                return HttpResponseNotAllowed(['GET', 'POST'])
            if request.method == 'GET':
                info = request.GET.dict()
            else:
                info = request.POST.dict()
            tokens = uri.split('/', 1)
            dataset = self.datasets.get(name=tokens[0])
            results = dataset.get_schema(request=request, *args, **kwargs)
            result_dict = {
                "status": "OK",
                "reason": "",
                "objects": results
            }
            return JsonResponse(result_dict)
        except Exception as e:
            result_dict = {
                "status": "Error",
                "reason": unicode(e),
                "objects": []
            }
            return ExceptionJsonResponse(result_dict)


    def data_view(self, request, uri, *args, **kwargs):
        """取数据接口(data)的Django View,
        Finalized on 20150826
        :param request:
        :param uri: 数据的uri
        :param args:
        :param kwargs:
        :return: 指定格式的数据文件, 或BadRequest, ServerError
        """
        try:
            if request.method not in ('GET', 'POST'):
                return HttpResponseNotAllowed(['GET', 'POST'])

            tokens = uri.split('/', 1)
            dataset = self.datasets.get(name=tokens[0])

            remove_on_finish = False

            if request.method == 'GET':
                get_dict = request.GET.dict()
            else:
                get_dict = request.POST.dict()

            api_key = get_dict.pop('api_key', None)
            ignore_cache = parse_bool(get_dict.pop('ignore_cache', False))

            cache_uri = uri
            savename_uri = uri

            if self.control == 'user':
                get_dict['user'] = request.user.username

            cache_kwarg_strs = []
            save_kwarg_strs = []
            for key, value in get_dict.iteritems():
                cache_kwarg_strs.append('%s=%s' % (key, value))
                if key not in {'user', 'format'}:
                    save_kwarg_strs.append('%s=%s' % (key, value))
            if len(cache_kwarg_strs) > 0:
                cache_uri = cache_uri + '?' + '&'.join(cache_kwarg_strs)

            if len(save_kwarg_strs) > 0:
                savename_uri = savename_uri + '?' + '&'.join(save_kwarg_strs)

            if ignore_cache:
                get_dict['cache'] = 'w'
            else:
                get_dict['cache'] = 'rw'

            if self.filecache_manager is None:
                tmp_fname = '/tmp/datakeeper_%s_%s_%s' % (
                    self.name, gen_uuid8(), datetime.now().strftime('%Y%m%d%H%M%S'))
                try:
                    fileinfo = dataset.get_file(uri, request=request, dest=tmp_fname, **get_dict)
                except GetFileError as e:
                    RM(tmp_fname)
                    raise e
                filepath = tmp_fname
                remove_on_finish = True
                save_name = '%s.%s' % (savename_uri, fileinfo['format'])
            else:
                cache = self.filecache_manager.get(cache_uri, when_not_exist=['create'])
                if ignore_cache and cache.size > 0:
                    cache.delete()
                    cache = self.filecache_manager.get(cache_uri, when_not_exist=['create'])
                filepath = cache.filepath
                if cache.size == 0:
                    tmp_path = get_tmppath()
                    try:
                        fileinfo = dataset.get_file(uri, dest=tmp_path, request=request, **get_dict)
                    except GetFileError as e:
                        cache.delete()
                        raise e
                    cache.update(size=filesize(tmp_path), filetype=fileinfo['filetype'], ext=fileinfo['format'])
                    MV(tmp_path, filepath)
                    cache.save()
                save_name = '%s.%s' % (savename_uri, cache.ext)

            sig_data_view.send(sender=DataKeeper, uri=uri, request=request, parameters=get_dict)
            return file_response(filepath, save_name=save_name, remove_on_finish=remove_on_finish)

        except Exception as e:
            return ErrorJsonResponse({"status": "Error", "type": unicode(type(e)), "reason": unicode(e)})

    def data_json(self, request, uri, get_dict, *args, **kwargs):
        """取数据接口(data)的Django View,
        Finalized on 20150826
        :param request:
        :param uri: 数据的uri
        :param args:
        :param kwargs:
        :return: 指定格式的数据文件, 或BadRequest, ServerError
        """
        tokens = uri.split('/', 1)
        dataset = self.datasets.get(name=tokens[0])

        remove_on_finish = False
        api_key = get_dict.pop('api_key', None)
        ignore_cache = parse_bool(get_dict.pop('ignore_cache', False))

        cache_uri = uri
        savename_uri = uri

        if self.control == 'user':
            get_dict['user'] = request.user.username

        cache_kwarg_strs = []
        save_kwarg_strs = []
        for key, value in get_dict.iteritems():
            cache_kwarg_strs.append('%s=%s' % (key, value))
            if key not in {'user', 'format'}:
                save_kwarg_strs.append('%s=%s' % (key, value))
        if len(cache_kwarg_strs) > 0:
            cache_uri = cache_uri + '?' + '&'.join(cache_kwarg_strs)

        if len(save_kwarg_strs) > 0:
            savename_uri = savename_uri + '?' + '&'.join(save_kwarg_strs)

        if ignore_cache:
            get_dict['cache'] = 'w'
        else:
            get_dict['cache'] = 'rw'

        if self.filecache_manager is None:
            tmp_fname = '/tmp/datakeeper_%s_%s_%s' % (
                self.name, gen_uuid8(), datetime.now().strftime('%Y%m%d%H%M%S'))
            try:
                fileinfo = dataset.get_file(uri, request=request, dest=tmp_fname, **get_dict)
            except GetFileError as e:
                RM(tmp_fname)
                raise e
            filepath = tmp_fname
            remove_on_finish = True
            save_name = '%s.%s' % (savename_uri, fileinfo['format'])
        else:
            cache = self.filecache_manager.get(cache_uri, when_not_exist=['create'])
            if ignore_cache and cache.size > 0:
                cache.delete()
                cache = self.filecache_manager.get(cache_uri, when_not_exist=['create'])
            filepath = cache.filepath
            if cache.size == 0:
                tmp_path = get_tmppath()
                try:
                    fileinfo = dataset.get_file(uri, dest=tmp_path, request=request, **get_dict)
                except GetFileError as e:
                    cache.delete()
                    raise e
                cache.update(size=filesize(tmp_path), filetype=fileinfo['filetype'], ext=fileinfo['format'])
                MV(tmp_path, filepath)
                cache.save()
            save_name = '%s.%s' % (savename_uri, cache.ext)

        sig_data_view.send(sender=DataKeeper, uri=uri, request=request, parameters=get_dict)
        # return file_response(filepath, save_name=save_name, remove_on_finish=remove_on_finish)
        # file=open(filepath, 'rb').read()
        return filepath
        # file = open(filepath, 'rb').read()
        # return json.loads(file)

    def data_view_json(self, request, uri, *args, **kwargs):
        try:
            if request.method not in ('GET', 'POST'):
                return HttpResponseNotAllowed(['GET', 'POST'])
            if request.method == 'GET':
                get_dict = request.GET.dict()
            else:
                get_dict = request.POST.dict()
            filepath = self.data_json(request, uri, get_dict, *args, **kwargs)
            file = open(filepath, 'rb').read()
            return JsonResponse(json.loads(file))

        except Exception as e:
            return ErrorJsonResponse({"status": "Error", "type": unicode(type(e)), "reason": unicode(e)})

